﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright company="Microsoft Corp." file="HpcSchedulerServiceClient.cs">
//   All rights reserved. See License.txt in the project root for license information.
// </copyright>
// 
// --------------------------------------------------------------------------------------------------------------------
namespace HpcSchedulerManagement
{
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
    using System.Xml;

    using Commands;
    using Common;
    using DataContracts;

    using RestClient;

    public class HpcSchedulerServiceClient : RestServiceClient, IHpcSchedulerServiceClient
    {
        private const string ContinuationTokenHeader = "x-ms-continuation-queryId";

        public HpcSchedulerServiceClient(IRestServiceContext serviceContext) : base(serviceContext)
        {
        }

        public async Task<int> CreateJob(string hpcClusterName, SchedulerJob job, RequestOptions requestOptions = null)
        {
            var response = await this.ExecuteCommand(
                                        () => new CreateJobCommand(this.ServiceContext as IHpcSchedulerServiceContext, hpcClusterName, job), 
                                        requestOptions);

            return this.GetIdFromResponse(response);
        }

        public async Task<int> CreateJob(string hpcClusterName, IDictionary<string, object> properties, RequestOptions requestOptions = null)
        {
            var response = await this.ExecuteCommand(
                                        () => new CreateJobCommand(this.ServiceContext as IHpcSchedulerServiceContext, hpcClusterName, properties),
                                        requestOptions);

            return this.GetIdFromResponse(response);
        }

        public async Task<IList<SchedulerJob>> ListJobs(string hpcClusterName, IEnumerable<string> properties, RequestOptions requestOptions = null)
        {
            string continuationToken = null;
            var result = new List<SchedulerJob>();

            do
            {
                var response = await this.ExecuteCommand(
                                                   () => new ListJobsCommand(this.ServiceContext as IHpcSchedulerServiceContext, hpcClusterName, properties),
                                                   requestOptions);

                var jobList = XmlHelper.Deserialize<ArrayOfObject>(response).Object;
                if (jobList != null && jobList.Count > 0)
                {
                   result.AddRange(jobList.Select(x => HpcDataContractsTranslator.JobFromArrayOfProperties(x.Properties)).ToList());
                }

                continuationToken = response.Headers[ContinuationTokenHeader];
            } 
            while (!string.IsNullOrEmpty(continuationToken));

            return result;
        }

        public async Task<SchedulerJob> GetJob(string hpcClusterName, int jobId, IEnumerable<string> properties, RequestOptions requestOptions = null)
        {
            var response = await this.ExecuteCommand(
                                               () => new GetJobCommand(this.ServiceContext as IHpcSchedulerServiceContext, hpcClusterName, jobId, properties),
                                               requestOptions);

            return HpcDataContractsTranslator.JobFromArrayOfProperties(XmlHelper.Deserialize<ArrayOfProperty>(response).Property);
        }

        public async Task CancelJob(string hpcClusterName, int jobId, string cancellationMessage, bool forced = false, RequestOptions requestOptions = null)
        {
            await this.ExecuteCommand(
                            () => new CancelJobCommand(this.ServiceContext as IHpcSchedulerServiceContext, hpcClusterName, jobId, cancellationMessage, forced), 
                            requestOptions);
        }

        public async Task<int> CreateTask(string hpcClusterName, int jobId, SchedulerTask task, RequestOptions requestOptions = null)
        {
            var response = await this.ExecuteCommand(
                                        () => new AddTaskCommand(this.ServiceContext as IHpcSchedulerServiceContext, hpcClusterName, jobId, task), 
                                        requestOptions);

            return this.GetIdFromResponse(response);
        }

        public async Task<int> CreateTask(string hpcClusterName, int jobId, IEnumerable<string> properties, RequestOptions requestOptions = null)
        {
            var response = await this.ExecuteCommand(
                                        () => new AddTaskCommand(this.ServiceContext as IHpcSchedulerServiceContext, hpcClusterName, jobId, null),
                                        requestOptions);

            return this.GetIdFromResponse(response);
        }

        public async Task<IList<SchedulerTask>> ListTasks(string hpcClusterName, int jobId, IEnumerable<string> properties, RequestOptions requestOptions = null)
        {
            string continuationToken = null;
            var result = new List<SchedulerTask>();

            do
            {
                var response = await this.ExecuteCommand(
                                                   () => new ListTasksCommand(this.ServiceContext as IHpcSchedulerServiceContext, hpcClusterName, jobId, properties), 
                                                   requestOptions);

                var taskList = XmlHelper.Deserialize<ArrayOfObject>(response).Object;
                if (taskList != null && taskList.Count > 0)
                {
                    result.AddRange(taskList.Select(x => HpcDataContractsTranslator.TaskFromArrayOfProperties(x.Properties)).ToList());
                }

                continuationToken = response.Headers[ContinuationTokenHeader];
            }
            while (!string.IsNullOrEmpty(continuationToken));

            return result;
        }

        public async Task<SchedulerTask> GetTask(string hpcClusterName, int jobId, int taskId, IEnumerable<string> properties, RequestOptions requestOptions = null)
        {
            var response = await this.ExecuteCommand(
                                               () => new GetTaskCommand(
                                                                this.ServiceContext as IHpcSchedulerServiceContext, 
                                                                hpcClusterName, 
                                                                jobId,
                                                                taskId,
                                                                properties), 
                                               requestOptions);

            return XmlHelper.Deserialize<SchedulerTask>(response);
        }

        public async Task SubmitJob(string hpcClusterName, int jobId, SchedulerJob job, NetworkCredential credential, RequestOptions requestOptions = null)
        {
            await this.ExecuteCommand(
                                () => new SubmitJobCommand(this.ServiceContext as IHpcSchedulerServiceContext, hpcClusterName, jobId, job, credential), 
                                requestOptions);
        }

        private int GetIdFromResponse(WebResponse response)
        {
            using (var streamReader = new StreamReader(response.GetResponseStream()))
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(streamReader.ReadToEnd());

                return int.Parse(xmlDocument.FirstChild.InnerText);
            }
        }
    }
}